/*
 * Copyright TLR Team, Inc. All Rights Reserved.
 */
package com.tlr.device.rest;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.tfb.rong.Device;
import com.tfb.service.UserAssessmentI;
import com.tfb.service.utility.JsonUtil;
import com.tfb.service.utility.Utils;
import com.tlr.device.model.HikiData;
import com.tlr.device.model.HikiDevice;
import com.tlr.device.model.HikiResponse;
import com.tlr.device.model.Result;
import com.tlr.device.service.DeviceDatabaseService;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonNode;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

@Path("/hike")
public class HikeControlService {

    private static final Logger log = Logger.getLogger(HikeControlService.class);
    @Context
    ServletContext context;
    DeviceDatabaseService deviceService;

    private synchronized void initDatabaseService() {
        if (deviceService == null) {
            ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(context);
            if (deviceService == null) {
                deviceService = (DeviceDatabaseService) ac.getBean("deviceDatabaseService");
            }
        }
    }

    @SuppressWarnings("UseSpecificCatch")
    private Result<String> postData(HikiDevice hiki) {
        try {
            Client client = Client.create();
            WebResource webResource = client.resource(AppContext.getHikeServerRest() + "/setstatus");
            String respStr = webResource.type(MediaType.APPLICATION_JSON).post(String.class, JsonUtil.writeValue(hiki));
            log.info("Hike Control service returned:" + respStr);
            JsonNode json = JsonUtil.createJson(respStr);
            if (json.has("code")) {
                return new Result<>(json.get("code").getIntValue(), json.get("message").asText());
            } else {
                return new Result<>(500, respStr);
            }
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "发送控制命令失败，设备可能不在线");
        }
    }

    @SuppressWarnings("UseSpecificCatch")
    private Result<HikiData> getData(String mac) {
        try {
            Client client = Client.create();
            WebResource webResource = client.resource(AppContext.getHikeServerRest() + "/data/" + mac);
            String content = webResource.accept(MediaType.APPLICATION_JSON).get(String.class);
            log.info("Hike data:" + content);
            HikiResponse resp = JsonUtil.readValue(content, HikiResponse.class);
            return new Result<>(resp.getCode(), resp.getMessage(), resp.getDeviceData());
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "不能获取设备数据");
        }
    }

    @SuppressWarnings("UseSpecificCatch")
    private Result<HikiDevice> getDevice(String mac) {
        try {
            Client client = Client.create();
            WebResource webResource = client.resource(AppContext.getHikeServerRest() + "/getdev/" + mac);
            String content = webResource.accept(MediaType.APPLICATION_JSON).get(String.class);
            log.info("Hike data:" + content);
            HikiResponse resp = JsonUtil.readValue(content, HikiResponse.class);
            return new Result<>(resp.getCode(), resp.getMessage(), resp.getDeviceStatus());
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, e.fillInStackTrace().getMessage());
        }
    }

    @Path("/wind")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> wind(@QueryParam("speed") int speed, @QueryParam("mac") String mac) {
        HikiDevice hiki = new HikiDevice();
        hiki.setSpeed(speed);
        hiki.setMac(mac);
        return postData(hiki);
    }

    @Path("/ion")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> ion(@QueryParam("on") int on, @QueryParam("mac") String mac) {
        HikiDevice hiki = new HikiDevice();
        hiki.setMac(mac);
        hiki.setAnion(on);
        return postData(hiki);
    }

    @Path("/switch")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> switch_(@QueryParam("on") int on, @QueryParam("mac") String mac) {
        HikiDevice hiki = new HikiDevice();
        hiki.setMac(mac);
        hiki.setState(on);
        return postData(hiki);
    }

    @Path("/mode")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> mode(@QueryParam("status") int status, @QueryParam("mac") String mac) {
        HikiDevice hiki = new HikiDevice();
        hiki.setMac(mac);
        hiki.setSleepstate(status);
        return postData(hiki);
    }

    @Path("hikeservice")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> getHikeSocketAddress(@Context HttpServletRequest request) {
        return new Result<>(0, "OK", AppContext.getHikeWebsocketAddress());
    }

    @Path("/hike_notify")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> hikeWebNotify(HikiDevice hikiDevice) {
        try {
            if (AppContext.getHikeSocketService() != null) {
                AppContext.getHikeSocketService().notifyMessage(hikiDevice);
            } else {
                log.info("No web socket is valid");
            }
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "Can't notify clients");
        }
    }

    @Path("/hike_data")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<HikiData> getHikiData(@QueryParam("mac") String mac) {
        try {
            return this.getData(mac);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "Can't notify clients");
        }
    }

    @Path("/all_hike_data")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<List<HikiData>> getAllHikiData() {
        try {
            initDatabaseService();
            List<HikiData> dataList = new ArrayList<>();
            List<Device> airPurifiers = deviceService.getAllDevice(4, 1);
            for (Device air : airPurifiers) {
                HikiData data = null;
                if (air.getDevicelang() == null
                    || air.getDevicelang().isEmpty()
                    || air.getDevicelati() == null
                    || air.getDevicelati().isEmpty()) {
                    continue;
                }
                Result<HikiData> realtimeData = this.getData(air.getDevicemac());
                if (realtimeData.getCode() != 0) {
                    log.warn("No realtime hiki data, error: " + realtimeData.getMessage() + ", try to get from database");
                    List<HikiData> result = deviceService.getDeviceMapper().selectLastHikiDataByMac(air.getDevicemac(), Utils.getNormalizedDate());
                    if (result.isEmpty()) {
                        log.info("Air device: " + air.getDevicemac() + " has no valid data in database");
                        data = null;
                    } else {
                        data = result.get(0);
                    }
                } else {
                    data = realtimeData.getData();
                }
                if (data != null) {
                    data.setLang(air.getDevicelang());
                    data.setLati(air.getDevicelati());
                    dataList.add(data);
                }
            }
            return new Result<>(0, "OK", dataList);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "Can't notify clients");
        }
    }

    @Path("/hike_status")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Result<HikiDevice> getHikiDevice(@QueryParam("mac") String mac) {
        try {
            return this.getDevice(mac);
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "Can't notify clients");
        }
    }

    @Path("/notify_data")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public Result<String> hikeWebNotify(HikiData data) {
        try {
            if (AppContext.getHikeSocketService() != null) {
                AppContext.getHikeSocketService().notifyMessage(data);
            } else {
                log.info("No web socket is valid");
            }
            return new Result<>(0, "OK");
        } catch (Exception e) {
            log.error(Utils.getFullException(e));
            return new Result<>(500, "Can't notify clients");
        }
    }

}
